package org.tuio.legacy
{
	import com.greensock.easing.Circ;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	import flash.utils.setTimeout;
	
	import k3.event.KEvent;
	
	import org.tuio.TuioClient;
	import org.tuio.TuioManager;
	import org.tuio.connectors.UDPConnector;
	import org.tuio.debug.TuioDebug;
	
	import udp.UdpManager;

	/**
	 * Legacy TUIOManager from fiducialtuioas3 (http://code.google.com/p/fiducialtuioas3/).
	 * 
	 * The functionality of TUIOManager is now integrated into <code>org.tuio.TuioManager</code> and 
	 * <code>org.tuio.ITuioFiducialReceiver</code>.  
	 * 
	 * @author Frederic Friess
	 * 
	 */
	public class TUIOManager extends Sprite{
		
		private var PropObjectDict:Dictionary;
		private var AliveDict:Dictionary;
		
		private var timeInMillisec:Number;
		private var 	 tuio:TuioClient; 
		public var connecter:UDPConnector;
		private var circles:Array=new Array();
		private var left:Number;
		private var right:Number;
		private var top:Number;
		private var bottom:Number;
		
		public function TUIOManager(){
			
			PropObjectDict = new Dictionary();
			AliveDict = new Dictionary();
			var RemoveChecker:Timer = new Timer(1000, 0);
			
			addEventListener(Event.ADDED_TO_STAGE, onStageAdd);
			
			RemoveChecker.addEventListener(TimerEvent.TIMER, timerHandler);
			RemoveChecker.start();
			
			
			this.timeInMillisec = 0;
		}
		
		public function close():void
		{
			connecter.close();
		}
		
		// for Hardware Test
		public function makeHotSpotImage(evt:KeyboardEvent):void{
			
			if(evt.charCode == Keyboard.ENTER){
//				trace("start:");
				var time:Date = new Date();
				this.timeInMillisec = (time.getSeconds()*1000) +  time.getMilliseconds();
			}
		}
		
		// for Hardware Test
		public function Touchhandler(evt:TouchEvent):void{
			var time:Date = new Date();
			var temp:Number = (time.getSeconds()*1000) +  time.getMilliseconds();
			//trace("Lag of "+String( ((temp - this.timeInMillisec)/1000))+" sek");
			//trace(evt.localX,evt.localY);
			this.timeInMillisec = 0;
		}
		
		private function onStageAdd(evt:Event=null):void{
			
			connecter=new UDPConnector();
			 tuio= 
				new TuioClient(connecter);
			var legacyListener:TuioLegacyListener = TuioLegacyListener.init(stage, tuio);
			var tuioDebug:TuioDebug = TuioDebug.init(stage);
			tuioDebug.showDebugText = false;
			tuioDebug.cursorLineColor = 0xcccccc;
			tuioDebug.cursorLineAlpha = 1;
			tuioDebug.cursorLineThickness = 5;
			
			var fiducialLegacyListener:FiducialTuioAS3LegacyListener = FiducialTuioAS3LegacyListener.init(stage, this);
			tuio.addListener(legacyListener);
			tuio.addListener(tuioDebug);
			tuio.addListener(fiducialLegacyListener);
			tuio.addListener(TuioManager.init(stage));
			
			//TuioManager.getInstance().addEventListener("add",handleAdd);
			//TuioManager.getInstance().addEventListener("update",handleUpdate);
			//TuioManager.getInstance().addEventListener("remove",handleRemove);
		
				
//			tuio.addListener(TuioFiducialDispatcher.init(stage,1000));
			
			stage.addEventListener(TouchEvent.MOUSE_DOWN, Touchhandler);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, makeHotSpotImage);
			
			removeEventListener(Event.ADDED_TO_STAGE, onStageAdd);
			
			left=50;
			top=50;
			right=stage.stageWidth-50;
			bottom=stage.stageHeight-50;
			var area:Shape=new Shape();
			this.addChild(area);
			area.x=left;
			area.y=top;
			area.graphics.beginFill(0x0095E0,1);
			area.graphics.drawRect(0,0,right-left,bottom-top);
			area.graphics.endFill();
		
			tuioDebug.left=left;
			tuioDebug.right=right;
			tuioDebug.top=top;
			tuioDebug.bottom=bottom;
			
		}
		
		
		private function findHitTest(newCircle:Circle):Boolean
		{
			var bmd1:BitmapData = new BitmapData(newCircle.width, newCircle.height, true, 0);
			bmd1.draw(newCircle);
			var bm1:Bitmap = new Bitmap(bmd1);
			bm1.x=newCircle.x;
			bm1.y=newCircle.y;
			
			
			for(var i:uint=0;i<circles.length;i++)
			{
				
				var oldCircle:Circle=circles[i];
				
				var bmd2:BitmapData = new BitmapData(oldCircle.width, oldCircle.height, true, 0);
				bmd2.draw(oldCircle);
				var bm2:Bitmap = new Bitmap(bmd2);
				bm2.x=oldCircle.x;
				bm2.y=oldCircle.y;
				
				if (bm1.bitmapData.hitTest(new Point(bm1.x, bm1.y), 80, bm2.bitmapData, new Point(bm2.x, bm2.y), 80))
				{
					
					bmd1.dispose();
					bmd2.dispose();
					
					return true;
				}
				else
				{
					bmd2.dispose();
				}
			
			}
			bmd1.dispose();
			return false;
		}
		
		private function removeCircle(id:int):void
		{
			var fined:Boolean=false;
			var index:int=0;
			var oldCircle:Circle;
			for(var i:uint=0;i<circles.length;i++)
			{
				 oldCircle=circles[i];
				if(oldCircle.id==id)
				{
					fined=true;
					index=i;
					break;
				}
			}
			if(fined)
			{
				//var str:String='{"type":2,"SessionID":'+oldCircle.id+',"xpos":'+oldCircle.x+',"ypos":'+oldCircle.y+'}';
				//UdpManager.send(str,"127.0.0.1",8000);
				setTimeout(removeAfterTime,500,id,oldCircle);
			}
		}
		
		private function removeAfterTime(id:int,circle:Circle):void
		{
			var fined:Boolean=false;
			var oldCircle:Circle;
			var index:int=0;
			for(var i:uint=0;i<circles.length;i++)
			{
				oldCircle=circles[i];
				if(oldCircle.id==id)
				{
					fined=true;
					index=i;
					break;
				}
			}
			if(fined)
			{
				
				circles.splice(index,1);
				circle.removeEventListener("remove",handleRemove);
				if(this.contains(circle))
				{
					this.removeChild(circle);
				}
			}
		}
		
		private function moveCircleById(id:int,x:int,y:int):void
		{
			for(var i:uint=0;i<circles.length;i++)
			{
				var oldCircle:Circle=circles[i];
				if(oldCircle.id==id)
				{
					oldCircle.x=x;
					oldCircle.y=y;
					break;
				}
			}
		}
		
		private function handleAdd(e:KEvent):void
		{
			var circle:Circle=new Circle();
			circle.x=e.obj[0];
			circle.y=e.obj[1];
			circle.id=e.obj[2];
			if(!findHitTest(circle))
			{
				this.addChild(circle);
				circle.addEventListener("remove",handleRemove);
				circles.push(circle);
				//var str:String='{"type":0,"SessionID":'+circle.id+',"xpos":'+circle.x+',"ypos":'+circle.y+'}';
				//UdpManager.send(str,"127.0.0.1",8000);

			}
			else
			{
				//trace("hit");
				
				circle=null;
			}
				
		}
		
		private function handleUpdate(e:KEvent):void
		{
			moveCircleById(e.obj[2],e.obj[0],e.obj[1]);
		}
		
		private function handleRemove(e:KEvent):void
		{
			
			removeCircle(e.obj[2]);
		}
		
		
		private function timerHandler(evt:TimerEvent):void{
			//speichern der statuse der Props vor der änderung
			var preAliveArray:Array = new Array();
			for (var f_id in PropObjectDict) {
				//trace(f_id+"----------")
				var prop:PropObject = PropObject(PropObjectDict[f_id]);
				if(prop.isActiv){
					preAliveArray.push(f_id);
				}else{
					preAliveArray.push(0);
				}
			}
			
			// alle auf 0 setzen
			var tempArray:Array = new Array();
			for (var f_id in PropObjectDict) {
				tempArray.push(0);
			}
			
			// alle deaktivieren
			for (var f_id in PropObjectDict) {
				var prop:PropObject = PropObject(PropObjectDict[f_id]); 
				prop.isActiv = false;
			}
			
		
			// die lebenden wieder aktivieren
			for (var f_id in PropObjectDict) {
				var prop:PropObject = PropObject(PropObjectDict[f_id]); 
				var s_id = prop.s_id;
				for (var alive_s_id in AliveDict){
					if(s_id == alive_s_id){
						prop.isActiv = true;
					}
				}
			}	
			AliveDict = new Dictionary();
			
			
			//speichern der statuse der Props nach der änderung
			var postAliveArray:Array = new Array();
			for (var f_id in PropObjectDict) {
				//trace(f_id+"----------")
				var prop:PropObject = PropObject(PropObjectDict[f_id]);
				if(prop.isActiv){
					postAliveArray.push(f_id);
				}else{
					postAliveArray.push(0);
				}
			}
			
			// die gestorbenen melden
			for (var i=0; i < postAliveArray.length; i++){
				if( (preAliveArray[i] != postAliveArray[i]) && (postAliveArray[i] == 0)){
					var f_id = preAliveArray[i];
					var prop:PropObject = PropObject(PropObjectDict[f_id]);
					prop.dispatchEvent(new PropEvent(PropEvent.REMOVE_PROP, prop.s_id, prop.f_id));
				}
			}
		}
		


		public function getProp(id:Number):PropObject{
			if (this.PropObjectDict[id] == null){
				
				var evt:PropEvent = new PropEvent(PropEvent.SET_PROP,-1,id);
				PropObjectDict[id] = createProp(evt);
			}
			return this.PropObjectDict[id];	
		}
		
		
		private function createProp(evt:PropEvent):PropObject{
			//var spr:PropView = new PropView();
			trace("createProp:"+evt.s_id+","+evt.f_id);
			trace(evt.xpos+","+evt.ypos);
			var tmpProp:PropObject = new PropObject(evt.s_id,evt.f_id);
			return tmpProp;
		}
	
		
		public function onPropSet(evt:PropEvent):void{
			if (PropObjectDict[evt.f_id] != null){
				
				var prop:PropObject = this.getProp(evt.f_id);
				prop.set_s_ID(evt.s_id);
				trace("onPropSet:"+evt.s_id+","+evt.f_id);
				trace(evt.xpos+","+evt.ypos);
				// onAdd ueberprüfen
				if (!prop.isActiv){
					prop.dispatchEvent(new PropEvent(PropEvent.ADD_PROP, evt.s_id,evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel, evt.raccel, evt.speed, true, true));
				}
				prop.isActiv = true;
		
				prop.dispatchEvent(new PropEvent(PropEvent.MOVE_PROP,			evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
				prop.dispatchEvent(new PropEvent(PropEvent.ROTATE_PROP, 		evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
				prop.dispatchEvent(new PropEvent(PropEvent.VELOCETY_MOVE_PROP, 	evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
				prop.dispatchEvent(new PropEvent(PropEvent.VELOCETY_ROTATE_PROP,evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
				prop.dispatchEvent(new PropEvent(PropEvent.ACCEL_MOVE_PROP, 	evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
				prop.dispatchEvent(new PropEvent(PropEvent.ACCEL_ROTATE_PROP, 	evt.s_id, evt.f_id, evt.xpos, evt.ypos, evt.angle, evt.xspeed, evt.yspeed, evt.rspeed, evt.maccel,evt.raccel,evt.speed,true,true));
			}
		}
		
		
		
		public function onPropAlive(evt:PropEvent):void{
			AliveDict[evt.s_id] = true;
		}
	}
}